package com.sf.fy.uav.applet.operate.controller;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.sf.fy.uav.common.awt.JwtUtil;
import com.sf.fy.uav.common.enums.ServicePrefixEnum;
import com.sf.fy.uav.common.enums.SettingStatusEnum;
import com.sf.fy.uav.common.enums.UserCouponSourceEnum;
import com.sf.fy.uav.common.enums.UserCouponStatusEnum;
import com.sf.fy.uav.common.response.operational.BannerResponse;
import com.sf.fy.uav.common.response.operational.HomePageInfoResponse;
import com.sf.fy.uav.common.response.operational.NewerCouponResponse;
import com.sf.fy.uav.common.response.operational.PopUpScreenResponse;
import com.sf.fy.uav.common.utils.RedisPrefixKey;
import com.sf.fy.uav.common.utils.Rs;
import com.sf.fy.uav.controller.*;
import com.sf.fy.uav.entity.*;
import com.sf.fy.uav.mapper.CouponActivityMapper;
import com.sf.fy.uav.mapper.CouponActivityRecordMapper;
import com.sf.fy.uav.mapper.CouponMapper;
import com.sf.fy.uav.mapper.UserCouponMapper;
import com.sf.fy.uav.order.controller.OrderInfoRest;
import com.sf.fy.uav.rest.BannerRest;
import com.sf.fy.uav.rest.CouponRest;
import com.sf.fy.uav.user.entity.User;
import com.sf.fy.uav.user.rest.UserRest;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.Operation;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

/**
 * @author LTQ
 */
@RestController
@Api(tags = "主页")
@RequestMapping("/home/page/")
public class HomePageController {


    @Autowired
    private BannerRest bannerRest;

    @Autowired
    private NoticeRest noticeRest;

    @Autowired
    private CouponActivityRecordController couponActivityRecordController;


    @Autowired
    private RedissonClient redissonClient;


    @Value("${lock.try_time:3}")
    private long lockTryTime;

    @Autowired
    private CouponActivityController couponActivityController;


    @Autowired
    private CouponActivityRecordMapper couponActivityRecordMapper;

    @Autowired
    private UserCouponRest userCouponRest;


    @Autowired
    private UserCouponMapper userCouponMapper;

    @Autowired
    private CouponActivityMapper couponActivityMapper;

    @Autowired
    private CouponActivityDetailController couponActivityDetailController;

    @Autowired
    private CouponRest couponRest;

    @Autowired
    private PopUpScreenRest popUpScreenRest;

    @Autowired
    private UserRest userRest;

    @Autowired
    private OrderInfoRest orderInfoRest;


    @Autowired
    private CouponMapper couponMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    private final static Logger logger = LoggerFactory.getLogger(HomePageController.class);

    @Operation(tags = "获取主页信息", description = "获取主页信息")
    @GetMapping("get-home-page-info")
    @CrossOrigin
    public Rs<HomePageInfoResponse> getHomePageInfo(@RequestParam(required = false) String token) {
        String userId = JwtUtil.getUserId(token);
        if (!ObjectUtils.isEmpty(userId)) {
            //正常用户才去发券
            User user = userRest.getNormalUser(userId);
            if (!ObjectUtils.isEmpty(user)) {
                Lock lock = null;
                try {
                    lock = redissonClient.getLock(ServicePrefixEnum.SAME_CITY + RedisPrefixKey.COUPON_ACTIVITY_RECORD + userId);
                    boolean b = lock.tryLock(lockTryTime, TimeUnit.SECONDS);
                    if (b) {
                        this.distributeNewerCoupon(userId);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    if (!org.springframework.util.ObjectUtils.isEmpty(lock)) {
                        // 释放锁
                        lock.unlock();
                    }
                }
            }
        }

        HomePageInfoResponse homePageInfoResponse = new HomePageInfoResponse();
        List<BannerResponse> bannerResponses = bannerRest.getBanners();
        homePageInfoResponse.setBannerResponses(bannerResponses);
        List<Notice> notices = noticeRest.getNotice();
        if (!CollectionUtils.isEmpty(notices)) {
            homePageInfoResponse.setNotice(notices.get(0).getContent());
        }
        List<NewerCouponResponse> newerCouponResponses = new ArrayList<>();
        if (!ObjectUtils.isEmpty(userId)) {
            List<CouponActivityRecord> couponActivityRecords = couponActivityRecordController.getNewerRecord(userId);
            if (!CollectionUtils.isEmpty(couponActivityRecords)) {
                couponActivityRecords.forEach(couponActivityRecord -> {
                    couponActivityRecord.setDisplayed(true);
                    couponActivityRecord.setUpdateTime(new Date());
                    couponActivityRecordMapper.updateById(couponActivityRecord);
                });
                List<String> ids = couponActivityRecords.stream().map(CouponActivityRecord::getCouponActivityId).collect(Collectors.toList());
                List<CouponActivityDetail> couponActivityDetails = couponActivityDetailController.getDetailsByCouponActivityIds(ids);

                if (!CollectionUtils.isEmpty(couponActivityDetails)) {
                    ids = couponActivityDetails.stream().map(CouponActivityDetail::getCouponId).collect(Collectors.toList());
                    List<UserCoupon> userCoupons = userCouponRest.getByCouponIdsAndUserId(ids, userId);
                    List<Coupon> coupons = couponMapper.selectBatchIds(ids);
                    for (CouponActivityDetail couponActivityDetail : couponActivityDetails) {
                        NewerCouponResponse newerCouponResponse = new NewerCouponResponse();
                        newerCouponResponse.setCouponName(couponActivityDetail.getCouponName());
                        newerCouponResponse.setCnt(couponActivityDetail.getCnt());
                        for (Coupon coupon : coupons) {
                            if (coupon.getId().equals(couponActivityDetail.getCouponId())) {
                                newerCouponResponse.setId(coupon.getId());
                                newerCouponResponse.setCouponType(coupon.getCouponType());
                                newerCouponResponse.setDiscount(coupon.getDiscount().doubleValue());
                                newerCouponResponse.setDescription(coupon.getDescription());
                                newerCouponResponse.setThreshold(coupon.getThreshold());
                                newerCouponResponse.setFailureTime(coupon.getFailureTime());
                                newerCouponResponse.setThresholdAmount(coupon.getThresholdAmount());
                                newerCouponResponse.setUpdateTime(coupon.getUpdateTime());
                            }
                        }
                        userCoupons.forEach(userCoupon -> {
                            if (couponActivityDetail.getCouponId().equals(userCoupon.getCouponId())) {
                                newerCouponResponse.setEffectiveTime(userCoupon.getEffectiveTime());
                                newerCouponResponse.setFailureTime(userCoupon.getExpireTime());
                            }
                        });
                        newerCouponResponses.add(newerCouponResponse);
                    }
                    //还要按照失效时间排序，后续补上
                    newerCouponResponses = newerCouponResponses.stream().sorted(Comparator.comparingDouble(NewerCouponResponse::getDiscount).thenComparing(NewerCouponResponse::getFailureTime).thenComparing(NewerCouponResponse::getUpdateTime, Comparator.reverseOrder())).collect(Collectors.toList());
                    homePageInfoResponse.setNewerCouponResponses(newerCouponResponses);
                    Integer cnt = couponActivityDetails.stream().map(CouponActivityDetail::getCnt).reduce(Integer::sum).get();
                    homePageInfoResponse.setTotalNewerCouponCnt(cnt);

                }
            }
            if (CollectionUtils.isEmpty(newerCouponResponses)) {
                List<PopUpScreenResponse> popUpScreenResponses = popUpScreenRest.getPopUpScreen();
                homePageInfoResponse.setPopUpScreenResponses(popUpScreenResponses);
            }
        }

        return Rs.success(homePageInfoResponse);
    }


    //独立新事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void distributeNewerCoupon(String userId) {
        System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
        /*
         * 1.校验是否有进行中的优惠券活动
         * 2.校验是否是新用户，新用户标准，没有任何已完成的订单
         * 3.检验该活动是否已经发过，如果发过不重复发放
         * 4.若新客发券活动中存在任一优惠券库存＜单次需发放数量,则活动设置为已下架，不发放优惠券
         */
        CouponActivity couponActivity = couponActivityController.getCouponActivity();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (!org.springframework.util.ObjectUtils.isEmpty(couponActivity)) {
            //查看是否已经领取过
            Long cnt = orderInfoRest.selectFinishOrder(userId);
            //校验是否是新用户
            if (cnt == 0) {
                String couponActivityId = couponActivity.getId();


                Long recordCnt = couponActivityRecordController.getRecordCnt(couponActivityId, userId);
                //校验是否已经发过
                if (recordCnt == 0) {
                    Date date = new Date();
                    //发放新人优惠券券包
                    CouponActivityRecord couponActivityRecord = new CouponActivityRecord();
                    couponActivityRecord.setCouponActivityId(couponActivity.getId());
                    couponActivityRecord.setUpdateTime(date);
                    couponActivityRecord.setCreateTime(date);
                    couponActivityRecord.setUserId(userId);
                    couponActivityRecordMapper.insert(couponActivityRecord);
                    //若新客发券活动中存在任一优惠券库存＜单次需发放数量,则活动设置为已下架，不发放优惠券
                    List<CouponActivityDetail> couponActivityDetails = couponActivityDetailController.getDetails(couponActivityId);
                    List<String> ids = couponActivityDetails.stream().map(CouponActivityDetail::getCouponId).collect(Collectors.toList());
                    List<Coupon> coupons = couponMapper.selectBatchIds(ids);
                    couponActivityDetails.forEach(couponActivityDetail -> {
                        logger.info("优惠券id:" + couponActivityDetail.getCouponId() + "扣减" + couponActivityDetail.getCnt());
                        //先去扣减库存，扣减成功再插入优惠券领取记录
                        Boolean isSuccess = couponRest.deductionOfInventory(couponActivityDetail.getCouponId(), date, couponActivityDetail.getCnt());
                        if (!isSuccess) {
                            couponActivity.setOffReason("优惠券" + couponActivityDetail.getCouponName() + "库存不足");
                            //库存不足,活动设置为已下架
                            this.downActivity(couponActivity, date);
                            //抛出异常，触发事务回滚
                            throw new RuntimeException("扣减库存失败");
                        }
                    });
                    //上面涉及的优惠券都扣减成功了，下面插入记录
                    couponActivityDetails.forEach(couponActivityDetail -> {
                        Integer num = couponActivityDetail.getCnt();
                        for (int i = 0; i < num; i++) {
                            UserCoupon userCoupon = new UserCoupon();
                            userCoupon.setCouponId(couponActivityDetail.getCouponId());
                            userCoupon.setStatus(UserCouponStatusEnum.NOT_USED.getValue());
                            userCoupon.setSource(UserCouponSourceEnum.NEWER.getValue());
                            userCoupon.setUpdateTime(date);
                            userCoupon.setCreateTime(date);
                            userCoupon.setUserId(userId);
                            coupons.forEach(coupon -> {
                                if (coupon.getId().equals(couponActivityDetail.getCouponId())) {
                                    userCoupon.setThreshold(coupon.getThreshold());
                                    userCoupon.setThresholdAmount(coupon.getThresholdAmount());
                                    Integer effectiveDays = coupon.getEffectiveDays();
                                    if (!org.apache.commons.lang3.ObjectUtils.isEmpty(effectiveDays)) {
                                        userCoupon.setEffectiveTime(date);
                                        //用户领取优惠券当日起+n-1天有效，n天截止时间为23:59:59
                                        Calendar calendar = Calendar.getInstance();
                                        calendar.setTime(date);
                                        calendar.add(Calendar.DAY_OF_YEAR, effectiveDays - 1);
                                        try {
                                            userCoupon.setExpireTime(sdf.parse(sdf.format(calendar.getTime()).substring(0, 10) + " 23:59:59"));
                                        } catch (ParseException e) {
                                            throw new RuntimeException(e);
                                        }
                                    } else {
                                        userCoupon.setEffectiveTime(coupon.getEffectiveTime());
                                        userCoupon.setExpireTime(coupon.getFailureTime());
                                    }
                                }
                            });
                            userCouponMapper.insert(userCoupon);
                        }

                    });

                }


            }


        }

    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void downActivity(CouponActivity couponActivity, Date date) {
        System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
        couponActivity.setStatus(SettingStatusEnum.OFF.getStatus());
        couponActivity.setUpdateTime(date);
        couponActivityMapper.updateById(couponActivity);

    }

}
